package com.sensor.meter.widget

import android.content.Context
import android.content.res.TypedArray
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Path
import android.graphics.RectF
import android.graphics.SweepGradient
import android.util.AttributeSet
import android.view.View
import com.sensor.meter.R
import com.sensor.meter.utils.dp2px
import com.sensor.meter.utils.sp2px
import java.text.DecimalFormat
import kotlin.math.min


/**
 * @author       CT
 * @date         2024/3/7
 * @description
 *
 */
class SoundMeterView constructor(context: Context,val attributeSet: AttributeSet?,val defStyleAttr:Int=0):View(context,attributeSet,defStyleAttr){

  constructor(context: Context,attributeSet: AttributeSet?):this(context,attributeSet,0)
  constructor(context: Context) : this(context,null,0)

  private val DEFAULT_COLOR_MIDDLE = Color.parseColor("#228fbd")
  private val DEFAULT_COLOR_TITLE = Color.WHITE
  private val DEFAULT_TEXT_SIZE_DIAL = 11.0f
  private val DEFAULT_STROKE_WIDTH = 2.0f
  private val DEFAULT_RADIUS_DIAL = 128.0f
  private val DEFAULT_TITLE_SIZE = 22.0f
  private val DEFAULT_ANIM_PLAY_TIME = 2000
  private val DEFAULT_BORDER = 5

  private var colorDialMiddle = 0
  private var textSizeDial = 0
  private var strokeWidthDial = 0
  private var titleDialSize = 0
  private var titleDialColor = 0
  private var animPlayTime = 0
  private var clockMinValue = 0
  private var dataUnit = "dB"
  // 底部开口的角度
  private val openAngle = 120.0f

  private var radiusDial = 0
  private var mRealRadius = 0

  private var arcPaint: Paint? = null
  private var mRect: RectF? = null
  private var pointerPaint: Paint? = null
  private var fontMetrics: Paint.FontMetrics? = null
  private var titlePaint: Paint? = null
  private var pointerPath: Path? = null

  init {
    //关闭硬件加速
    setLayerType(LAYER_TYPE_SOFTWARE, null);
    initAttr()
    initPaint()

  }

  // 初始化属性
  private fun initAttr() {
    val attributes: TypedArray = context.obtainStyledAttributes(attributeSet, R.styleable.SoundMeterView)
    colorDialMiddle = attributes.getColor(R.styleable.SoundMeterView_color_dial_middle, DEFAULT_COLOR_MIDDLE)
    textSizeDial = attributes.getDimension(R.styleable.SoundMeterView_text_size_dial, context.sp2px(DEFAULT_TEXT_SIZE_DIAL)).toInt()
    strokeWidthDial = attributes.getDimension(R.styleable.SoundMeterView_stroke_width_dial, context.dp2px(DEFAULT_STROKE_WIDTH)).toInt()
    radiusDial = attributes.getDimension(R.styleable.SoundMeterView_radius_circle_dial, context.dp2px(DEFAULT_RADIUS_DIAL)).toInt()
    titleDialSize = attributes.getDimension(R.styleable.SoundMeterView_text_title_size, context.dp2px(DEFAULT_TITLE_SIZE)).toInt()
    titleDialColor = attributes.getColor(R.styleable.SoundMeterView_text_title_color, DEFAULT_COLOR_TITLE)
    animPlayTime = attributes.getInt(R.styleable.SoundMeterView_animator_play_time, DEFAULT_ANIM_PLAY_TIME)
    attributes.recycle()
  }

  // 初始化画笔
  private fun initPaint(){
    arcPaint = Paint(Paint.ANTI_ALIAS_FLAG)
    arcPaint!!.style=Paint.Style.STROKE
    arcPaint!!.strokeWidth=strokeWidthDial.toFloat()
    arcPaint!!.setShadowLayer(10f, 0f, 0f, Color.parseColor("#35FCFB"))
    //
    pointerPaint = Paint(Paint.ANTI_ALIAS_FLAG)
    pointerPaint!!.textSize=textSizeDial.toFloat()
    pointerPaint!!.textAlign=Paint.Align.CENTER
    fontMetrics = pointerPaint!!.fontMetrics
    //
    titlePaint = Paint(Paint.ANTI_ALIAS_FLAG)
    titlePaint!!.textAlign=Paint.Align.CENTER
    titlePaint!!.isFakeBoldText=true
    //
    pointerPath = Path()
    mRect= RectF()
  }

  open var currentValue:Float=0.0f
    get()=field
    set(value){
      field=value
      postInvalidate()
    }

  /**
   * 刻度最大值
   */
  private var clockPointNum:Int=100
    get() = field
    set(value:Int){
      field=value
      postInvalidate()
    }

  /**
   * 设置表盘刻度最大最小值
   * @param clockMaxValue Int
   * @param clockMinValue Int
   * @param dataUnit String?
   */
  fun setClockValueArea(clockMaxValue: Int, clockMinValue: Int,dataUnit: String?) {
    this.clockMinValue = clockMinValue
    this.dataUnit = dataUnit!!
    this.clockPointNum=(clockMaxValue - clockMinValue)
  }


  override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec)
    val widthMode = MeasureSpec.getMode(widthMeasureSpec)
    val widthSize = MeasureSpec.getSize(widthMeasureSpec)
    val heightMode = MeasureSpec.getMode(heightMeasureSpec)
    val heightSize = MeasureSpec.getSize(heightMeasureSpec)

    var mWidth:Int?
    var mHeight:Int?
    if (widthMode == MeasureSpec.EXACTLY) {
      mWidth = widthSize
    } else {
      mWidth = paddingLeft + radiusDial * 2 + paddingRight
      if (widthMode == MeasureSpec.AT_MOST) {
        mWidth = min(mWidth, widthSize)
      }
    }

    if (heightMode == MeasureSpec.EXACTLY) {
      mHeight = heightSize
    } else {
      mHeight = paddingTop + radiusDial * 2 + paddingBottom
      if (heightMode == MeasureSpec.AT_MOST) {
        mHeight = min(mHeight, heightSize)
      }
    }
    //
    setMeasuredDimension(mWidth, mHeight)
    //
    radiusDial = min((measuredWidth - paddingLeft - paddingRight), (measuredHeight - paddingTop - paddingBottom)) / 2
    mRealRadius = radiusDial - strokeWidthDial / 2 - DEFAULT_BORDER * 2
    mRect!![(-mRealRadius - DEFAULT_BORDER).toFloat(), (-mRealRadius - DEFAULT_BORDER).toFloat(),
      (mRealRadius + DEFAULT_BORDER).toFloat()]=(mRealRadius + DEFAULT_BORDER).toFloat()
  }


  override fun onDraw(canvas: Canvas) {
    super.onDraw(canvas)
    //画圆弧
    drawArc(canvas);
    //绘制刻度和数字
    drawPointerLine(canvas);
    // 画指针阴影
    drawPointShadow(canvas);
    //绘制中间黑色圆形背景
    drawBlackCircle(canvas);
    //绘制表针
    drawPointer(canvas);
    //绘制深蓝色发光圆形
    drawBlueCircle(canvas);
    //绘制表盘中的数字
    drawCircleText(canvas);
  }

  private fun drawArc(canvas: Canvas) {
    canvas.translate((paddingLeft + radiusDial).toFloat(), (paddingTop + radiusDial).toFloat())
    arcPaint!!.setShader(null)
    arcPaint!!.style = Paint.Style.STROKE
    arcPaint!!.isAntiAlias = true
    arcPaint!!.setAlpha(70)
    arcPaint!!.strokeWidth = strokeWidthDial.toFloat()
    arcPaint!!.setShadowLayer(10f, 0f, 0f, Color.WHITE)
    arcPaint!!.color=Color.parseColor("#38F9FD")
    canvas.drawArc(mRect!!, 150f, 360.0f - openAngle, false, arcPaint!!)
  }

  private fun drawPointerLine(canvas: Canvas) {
    //旋转画布 （坐标系）
    canvas.rotate(150f)
    for (i in 0 until clockPointNum + 1) {
      pointerPaint!!.setColor(colorDialMiddle)
      if (i % 10 == 0) {     //长表针
        pointerPaint!!.strokeWidth = 3f
        canvas.drawLine((radiusDial - DEFAULT_BORDER - strokeWidthDial).toFloat(), 0f, radiusDial - strokeWidthDial - context.dp2px(15.0f), 0f, pointerPaint!!)
        drawPointerText(canvas, i)
      } else if ((i % 5).toFloat() == 0f) {    //短表针
        pointerPaint!!.strokeWidth = 2f
        canvas.drawLine((radiusDial - DEFAULT_BORDER - strokeWidthDial).toFloat(), 0f, radiusDial - strokeWidthDial - context.dp2px(9.0f), 0f, pointerPaint!!)
      }
      canvas.rotate((360 - openAngle) / clockPointNum)
    }
    canvas.rotate(-((180 - openAngle) / 2 + (360 - openAngle) / clockPointNum))
  }

  private fun drawPointerText(canvas: Canvas, i: Int) {
    canvas.save()
    pointerPaint!!.color=Color.parseColor("#38F9FD")
    canvas.translate((radiusDial - strokeWidthDial - context.dp2px(21.0f) - pointerPaint!!.measureText(i.toString()) / 2).toFloat(), 0f)
    //坐标系总旋转角度为360度
    canvas.rotate(360 - 150 - (360 - openAngle) / clockPointNum * i)
    val textBaseLine = (0 + (fontMetrics!!.bottom - fontMetrics!!.top) / 2 - fontMetrics!!.bottom).toInt()
    // 表盘高刻度值
    canvas.drawText((i + clockMinValue).toString(), 0f, textBaseLine.toFloat(), pointerPaint!!)
    canvas.restore()
  }

  private fun drawPointShadow(canvas: Canvas) {
    val currentDegree =(currentValue - clockMinValue) * ((360 - openAngle) / clockPointNum) + 150
    canvas.rotate(currentDegree)

    val colorSweep = intArrayOf(0xAAFFE9EC.toInt(), 0x0028E9EC, 0xAA28E9EC.toInt())
    val position = floatArrayOf(0f, 0.9f, 1f)

    val mShader = SweepGradient(0f, 0f, colorSweep, position)
    arcPaint!!.setShader(mShader)
    arcPaint!!.style = Paint.Style.STROKE
    arcPaint!!.strokeWidth = radiusDial * 0.4f
    arcPaint!!.clearShadowLayer()
    val mRect = RectF(
      (-mRealRadius - DEFAULT_BORDER + radiusDial * 0.2f) as Float, (-mRealRadius - DEFAULT_BORDER + radiusDial * 0.2f) as Float,
      (mRealRadius + DEFAULT_BORDER - radiusDial * 0.2f) as Float, (mRealRadius + DEFAULT_BORDER - radiusDial * 0.2f) as Float
    )
    canvas.drawArc(mRect, 360 - (currentDegree - 150), currentDegree - 150, false, arcPaint!!)
  }

  private fun drawBlackCircle(canvas: Canvas) {
    canvas.restore()
    canvas.translate((paddingLeft + radiusDial).toFloat(), (paddingTop + radiusDial).toFloat())
    val pointerPaint = Paint()
    pointerPaint.isAntiAlias = true
    pointerPaint.style = Paint.Style.FILL
    pointerPaint.setColor(Color.parseColor("#05002D"))
    canvas.drawCircle(0f, 0f, (radiusDial * 0.6).toFloat(), pointerPaint)
  }

  private fun drawPointer(canvas: Canvas) {
    canvas.save()
    val currentDegree = (currentValue - clockMinValue) * ((360 - openAngle) / clockPointNum) + 150
    canvas.rotate(currentDegree)
    titlePaint!!.color=Color.WHITE
    titlePaint!!.isAntiAlias = true
    pointerPath!!.moveTo(radiusDial - context.dp2px(12.0f), 0f)
    pointerPath!!.lineTo(0f, -context.dp2px(5.0f))
    pointerPath!!.lineTo(-12f, 0f)
    pointerPath!!.lineTo(0f, context.dp2px(5f))
    pointerPath!!.close()
    canvas.drawPath(pointerPath!!, titlePaint!!)
    canvas.save()
    canvas.restore()
  }

  private fun drawBlueCircle(canvas: Canvas) {
    canvas.rotate(0f)
    canvas.restore()
    val pointerPaint = Paint()
    pointerPaint.isAntiAlias = true
    pointerPaint.style = Paint.Style.FILL
    pointerPaint.setColor(Color.parseColor("#050D3D"))
    pointerPaint.setShadowLayer(15f, 0f, 0f, Color.parseColor("#006EC6"))
    canvas.drawCircle(0f, 0f, radiusDial * 0.4f, pointerPaint)
  }

  private fun drawCircleText(canvas: Canvas) {
    // 当前值
    titlePaint!!.color=titleDialColor
    titlePaint!!.textSize = titleDialSize.toFloat()
    canvas.drawText(formatData(currentValue), 0f, 0f, titlePaint!!)
    //单位
    titlePaint!!.color=Color.parseColor("#38F9FD")
    titlePaint!!.textSize = context.sp2px(14f)
    canvas.drawText("($dataUnit)", 0f, context.dp2px(18f), titlePaint!!)
  }

  private fun formatData(num: Float): String {
    val decimalFormat = DecimalFormat("###.#")
    return decimalFormat.format(num)
  }

}